﻿using Nop.Core;
using Nop.Core.Domain.Customers;
using Nop.Core.Domain.XJ;
using Nop.Services.Common;
using Nop.Services.Customers;
using Nop.Services.ExportImport.Help;
using Nop.Services.Media;
using Nop.Services.Stores;
using OfficeOpenXml;
using OfficeOpenXml.Style;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;

namespace Nop.Services.ExportImport
{
	/// <summary>
	/// Export manager
	/// </summary>
	public partial class ExportManager : IExportManager
	{
		#region Fields

		private readonly ICustomerService _customerService;
		private readonly IPictureService _pictureService;
		private readonly IStoreService _storeService;
		private readonly IWorkContext _workContext;
		private readonly IGenericAttributeService _genericAttributeService;

		#endregion

		#region Ctor

		public ExportManager(
			ICustomerService customerService,
			IPictureService pictureService,
			IStoreService storeService,
			IWorkContext workContext,
			IGenericAttributeService genericAttributeService)
		{
			this._customerService = customerService;
			this._pictureService = pictureService;
			this._storeService = storeService;
			this._workContext = workContext;
			this._genericAttributeService = genericAttributeService;
		}

		#endregion

		#region Utilities


		protected virtual void SetCaptionStyle(ExcelStyle style)
		{
			style.Fill.PatternType = ExcelFillStyle.Solid;
			style.Fill.BackgroundColor.SetColor(Color.FromArgb(184, 204, 228));
			style.Font.Bold = true;
		}

		/// <summary>
		/// Returns the path to the image file by ID
		/// </summary>
		/// <param name="pictureId">Picture ID</param>
		/// <returns>Path to the image file</returns>
		protected virtual string GetPictures(int pictureId)
		{
			var picture = _pictureService.GetPictureById(pictureId);
			return _pictureService.GetThumbLocalPath(picture);
		}

		private bool IgnoreExportCategoryProperty()
		{
			return !_workContext.CurrentCustomer.GetAttribute<bool>("category-advanced-mode");
		}

		private bool IgnoreExportManufacturerProperty()
		{
			return !_workContext.CurrentCustomer.GetAttribute<bool>("manufacturer-advanced-mode");
		}

		/// <summary>
		/// Export objects to XLSX
		/// </summary>
		/// <typeparam name="T">Type of object</typeparam>
		/// <param name="properties">Class access to the object through its properties</param>
		/// <param name="itemsToExport">The objects to export</param>
		/// <returns></returns>
		protected virtual byte[] ExportToXlsx<T>(PropertyByName<T>[] properties, IEnumerable<T> itemsToExport)
		{
			using (var stream = new MemoryStream())
			{
				// ok, we can run the real code of the sample now
				using (var xlPackage = new ExcelPackage(stream))
				{
					// uncomment this line if you want the XML written out to the outputDir
					//xlPackage.DebugMode = true; 

					// get handles to the worksheets
					var worksheet = xlPackage.Workbook.Worksheets.Add(typeof(T).Name);
					var fWorksheet = xlPackage.Workbook.Worksheets.Add("DataForFilters");
					fWorksheet.Hidden = eWorkSheetHidden.VeryHidden;

					//create Headers and format them 
					var manager = new PropertyManager<T>(properties.Where(p => !p.Ignore));
					manager.WriteCaption(worksheet, SetCaptionStyle);

					var row = 2;
					foreach (var items in itemsToExport)
					{
						manager.CurrentObject = items;
						manager.WriteToXlsx(worksheet, row++, false, fWorksheet: fWorksheet);
					}

					xlPackage.Save();
				}
				return stream.ToArray();
			}
		}


		//private string GetCustomCustomerAttributes(Customer customer)
		//{
		//    var selectedCustomerAttributes = customer.GetAttribute<string>(SystemCustomerAttributeNames.CustomCustomerAttributes, _genericAttributeService);
		//    return _customerAttributeFormatter.FormatAttributes(selectedCustomerAttributes, ";");
		//}

		#endregion

		#region Methods

		/// <summary>
		/// Export customer list to XLSX
		/// </summary>
		/// <param name="customers">Customers</param>
		public virtual byte[] ExportCustomersToXlsx(IList<Customer> customers)
		{
			//property array
			var properties = new[]
			{
				new PropertyByName<Customer>("CustomerId", p => p.Id),
				new PropertyByName<Customer>("CustomerGuid", p => p.CustomerGuid),
				new PropertyByName<Customer>("Username", p => p.Username),
				new PropertyByName<Customer>("TrueName", p => p.TrueName),
				new PropertyByName<Customer>("Password", p => _customerService.GetCurrentPassword(p.Id).Return(password => password.Password, null)),
				new PropertyByName<Customer>("PasswordFormatId", p => _customerService.GetCurrentPassword(p.Id).Return(password => password.PasswordFormatId, 0)),
				new PropertyByName<Customer>("PasswordSalt", p => _customerService.GetCurrentPassword(p.Id).Return(password => password.PasswordSalt, null)),
				new PropertyByName<Customer>("Active", p => p.Active),
				new PropertyByName<Customer>("IsGuest", p => p.IsGuest()),
				new PropertyByName<Customer>("IsRegistered", p => p.IsRegistered()),
				new PropertyByName<Customer>("IsAdministrator", p => p.IsAdmin()),
				new PropertyByName<Customer>("CreatedOnUtc", p => p.CreatedOnUtc),
                ////attributes
                //new PropertyByName<Customer>("Gender", p => p.GetAttribute<string>(SystemCustomerAttributeNames.Gender)),
                //new PropertyByName<Customer>("StreetAddress", p => p.GetAttribute<string>(SystemCustomerAttributeNames.StreetAddress)),
                //new PropertyByName<Customer>("ZipPostalCode", p => p.GetAttribute<string>(SystemCustomerAttributeNames.ZipPostalCode)),
                //new PropertyByName<Customer>("City", p => p.GetAttribute<string>(SystemCustomerAttributeNames.City)),
                //new PropertyByName<Customer>("CountryId", p => p.GetAttribute<int>(SystemCustomerAttributeNames.CountryId)),
                //new PropertyByName<Customer>("StateProvinceId", p => p.GetAttribute<int>(SystemCustomerAttributeNames.StateProvinceId)),
                //new PropertyByName<Customer>("TimeZoneId", p => p.GetAttribute<string>(SystemCustomerAttributeNames.TimeZoneId)),
                //new PropertyByName<Customer>("AvatarPictureId", p => p.GetAttribute<int>(SystemCustomerAttributeNames.AvatarPictureId)),
                //new PropertyByName<Customer>("ForumPostCount", p => p.GetAttribute<int>(SystemCustomerAttributeNames.ForumPostCount)),
                //new PropertyByName<Customer>("Signature", p => p.GetAttribute<string>(SystemCustomerAttributeNames.Signature)),
                //new PropertyByName<Customer>("CustomCustomerAttributes",  GetCustomCustomerAttributes)
            };

			return ExportToXlsx(properties, customers);
		}

		/// <summary>
		/// Export customer list to xml
		/// </summary>
		/// <param name="customers">Customers</param>
		/// <returns>Result in XML format</returns>
		public virtual string ExportCustomersToXml(IList<Customer> customers)
		{
			var sb = new StringBuilder();
			var stringWriter = new StringWriter(sb);
			var xmlWriter = new XmlTextWriter(stringWriter);
			xmlWriter.WriteStartDocument();
			xmlWriter.WriteStartElement("Customers");
			xmlWriter.WriteAttributeString("Version", NopVersion.CurrentVersion);

			foreach (var customer in customers)
			{
				xmlWriter.WriteStartElement("Customer");
				xmlWriter.WriteElementString("CustomerId", null, customer.Id.ToString());
				xmlWriter.WriteElementString("CustomerGuid", null, customer.CustomerGuid.ToString());
				xmlWriter.WriteElementString("Username", null, customer.Username);

				var customerPassword = _customerService.GetCurrentPassword(customer.Id);
				xmlWriter.WriteElementString("Password", null, customerPassword.Return(password => password.Password, null));
				xmlWriter.WriteElementString("PasswordFormatId", null, customerPassword.Return(password => password.PasswordFormatId, 0).ToString());
				xmlWriter.WriteElementString("PasswordSalt", null, customerPassword.Return(password => password.PasswordSalt, null));

				xmlWriter.WriteElementString("Active", null, customer.Active.ToString());

				xmlWriter.WriteElementString("IsGuest", null, customer.IsGuest().ToString());
				xmlWriter.WriteElementString("IsRegistered", null, customer.IsRegistered().ToString());
				xmlWriter.WriteElementString("IsAdministrator", null, customer.IsAdmin().ToString());
				xmlWriter.WriteElementString("CreatedOnUtc", null, customer.CreatedOnUtc.ToString());

				//xmlWriter.WriteElementString("FirstName", null, customer.GetAttribute<string>(SystemCustomerAttributeNames.FirstName));
				//xmlWriter.WriteElementString("LastName", null, customer.GetAttribute<string>(SystemCustomerAttributeNames.LastName));
				xmlWriter.WriteElementString("TrueName", null, customer.TrueName);
				xmlWriter.WriteElementString("Gender", null, customer.GetAttribute<string>(SystemCustomerAttributeNames.Gender));
				xmlWriter.WriteElementString("CountryId", null, customer.GetAttribute<int>(SystemCustomerAttributeNames.CountryId).ToString());
				xmlWriter.WriteElementString("StreetAddress", null, customer.GetAttribute<string>(SystemCustomerAttributeNames.StreetAddress));
				xmlWriter.WriteElementString("ZipPostalCode", null, customer.GetAttribute<string>(SystemCustomerAttributeNames.ZipPostalCode));
				xmlWriter.WriteElementString("City", null, customer.GetAttribute<string>(SystemCustomerAttributeNames.City));
				xmlWriter.WriteElementString("StateProvinceId", null, customer.GetAttribute<int>(SystemCustomerAttributeNames.StateProvinceId).ToString());

				xmlWriter.WriteElementString("AvatarPictureId", null, customer.GetAttribute<int>(SystemCustomerAttributeNames.AvatarPictureId).ToString());
				xmlWriter.WriteElementString("ForumPostCount", null, customer.GetAttribute<int>(SystemCustomerAttributeNames.ForumPostCount).ToString());
				xmlWriter.WriteElementString("Signature", null, customer.GetAttribute<string>(SystemCustomerAttributeNames.Signature));

				var selectedCustomerAttributesString = customer.GetAttribute<string>(SystemCustomerAttributeNames.CustomCustomerAttributes, _genericAttributeService);

				if (!string.IsNullOrEmpty(selectedCustomerAttributesString))
				{
					var selectedCustomerAttributes = new StringReader(selectedCustomerAttributesString);
					var selectedCustomerAttributesXmlReader = XmlReader.Create(selectedCustomerAttributes);
					xmlWriter.WriteNode(selectedCustomerAttributesXmlReader, false);
				}

				xmlWriter.WriteEndElement();
			}

			xmlWriter.WriteEndElement();
			xmlWriter.WriteEndDocument();
			xmlWriter.Close();
			return stringWriter.ToString();
		}

		public virtual byte[] ExportPlacesToXlsx(IList<XJPlace> places)
		{
			//property array
			var properties = new[]
			{
				new PropertyByName<XJPlace>("ID", p => p.Id),
				new PropertyByName<XJPlace>("名称", p => p.Name),
				new PropertyByName<XJPlace>("具体位置", p => p.Location),
				new PropertyByName<XJPlace>("发布", p => p.Published?"是":"否"),
				new PropertyByName<XJPlace>("显示顺序", p => p.DisplayOrder),
			};

			return ExportToXlsx(properties, places);
		}

		public virtual byte[] ExportConsumablesToXlsx(IList<XJEquipmentTemp> consumables)
		{
			//property array
			var properties = new[]
			{
				new PropertyByName<XJEquipmentTemp>("ID", p => p.Id),
				new PropertyByName<XJEquipmentTemp>("一级分类", p => p.ParentCategoryName),
				new PropertyByName<XJEquipmentTemp>("二级分类", p => p.CategoryName),
				new PropertyByName<XJEquipmentTemp>("名称", p => p.Name),
				new PropertyByName<XJEquipmentTemp>("品牌", p => p.Manufacturer),
				new PropertyByName<XJEquipmentTemp>("规格型号", p => p.Specification),
				new PropertyByName<XJEquipmentTemp>("单价", p => p.Price),
				new PropertyByName<XJEquipmentTemp>("当前库存", p => p.Stock),
				new PropertyByName<XJEquipmentTemp>("单位", p => p.Unit),
			};

			return ExportToXlsx(properties, consumables);
		}

		public virtual byte[] ExportMaintenanceToXlsx(IList<XJMaintenanceTemp> items)
		{
			//property array
			var properties = new[]
			{
				new PropertyByName<XJMaintenanceTemp>("维修编号", p => p.SNo),
				new PropertyByName<XJMaintenanceTemp>("计划编号", p => p.PNo),
				new PropertyByName<XJMaintenanceTemp>("巡检点", p => p.PlaceName),
				new PropertyByName<XJMaintenanceTemp>("设备分类", p => p.CategoryName),
				new PropertyByName<XJMaintenanceTemp>("设备名称", p => p.EquipmentNames),
				new PropertyByName<XJMaintenanceTemp>("情况说明", p => p.Comment),
				new PropertyByName<XJMaintenanceTemp>("发起部门", p => p.DepartmentName),
				new PropertyByName<XJMaintenanceTemp>("发起人", p => p.CustomerName),
				new PropertyByName<XJMaintenanceTemp>("责任部门", p => p.ResponsibleDepartmentName),
				new PropertyByName<XJMaintenanceTemp>("责任班组", p => p.ResponsibleTeamName),
				new PropertyByName<XJMaintenanceTemp>("责任人", p => p.ResponsiblePersonName),
				new PropertyByName<XJMaintenanceTemp>("维修人", p => p.MaintenancePersonNames),
				new PropertyByName<XJMaintenanceTemp>("是外援实施", p => p.IsExternal?"是":""),
				new PropertyByName<XJMaintenanceTemp>("维修费用", p => p.Total),
				new PropertyByName<XJMaintenanceTemp>("开始时间", p => p.CreatedOn.ToString("yyyy-MM-dd HH:mm")),
				new PropertyByName<XJMaintenanceTemp>("完工时间", p => p.MaintenanceOn.HasValue?p.MaintenanceOn.Value.ToString("yyyy-MM-dd HH:mm"):""),
				new PropertyByName<XJMaintenanceTemp>("工时", p => p.HoursString),
				new PropertyByName<XJMaintenanceTemp>("评分", p => p.Star),
				new PropertyByName<XJMaintenanceTemp>("评价内容", p => p.Evaluation),
				new PropertyByName<XJMaintenanceTemp>("状态", p => p.StateName),
			};

			return ExportToXlsx(properties, items);
		}

		public virtual byte[] ExportMaintenanceReportByUserToXlsx(IList<MaintenanceReportByUser> items)
		{
			//property array
			var properties = new[]
			{
				new PropertyByName<MaintenanceReportByUser>("姓名", p => p.TrueName),
				new PropertyByName<MaintenanceReportByUser>("部门", p => p.DepartmentName),
				new PropertyByName<MaintenanceReportByUser>("班组", p => p.TeamName),
				new PropertyByName<MaintenanceReportByUser>("共计工时", p => p.HoursString),
				new PropertyByName<MaintenanceReportByUser>("共计次数", p => p.Amount),
				new PropertyByName<MaintenanceReportByUser>("平均工时", p => p.Per),
				new PropertyByName<MaintenanceReportByUser>("月度总工时", p => p.MonthHours),
				new PropertyByName<MaintenanceReportByUser>("月度工作效率", p => p.Efficiency),
			};

			return ExportToXlsx(properties, items);
		}

		public virtual byte[] ExportMaintenanceReportByEquipmentToXlsx(IList<MaintenanceReportByEquipment> items)
		{
			//property array
			var properties = new[]
			{
				new PropertyByName<MaintenanceReportByEquipment>("名称", p => p.Name),
				new PropertyByName<MaintenanceReportByEquipment>("品牌", p => p.Manufacturer),
				new PropertyByName<MaintenanceReportByEquipment>("规格型号", p => p.Specification),
				new PropertyByName<MaintenanceReportByEquipment>("共计工时", p => p.HoursString),
				new PropertyByName<MaintenanceReportByEquipment>("共计次数", p => p.Amount),
				new PropertyByName<MaintenanceReportByEquipment>("平均工时", p => p.Per),
			};

			return ExportToXlsx(properties, items);
		}

		public virtual byte[] ExportStockOutReportByEquipmentToXlsx(IList<StockOutReportByEquipment> items)
		{
			//property array
			var properties = new[]
			{
				new PropertyByName<StockOutReportByEquipment>("名称", p => p.Name),
				new PropertyByName<StockOutReportByEquipment>("品牌", p => p.Manufacturer),
				new PropertyByName<StockOutReportByEquipment>("规格型号", p => p.Specification),
				new PropertyByName<StockOutReportByEquipment>("数量", p => p.Amount),
				new PropertyByName<StockOutReportByEquipment>("单价", p => p.Price),
				new PropertyByName<StockOutReportByEquipment>("小计", p => p.Total),
			};

			return ExportToXlsx(properties, items);
		}

		#endregion
	}
}
